package edu.mse.camel.client.uml.collab.emflistener;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.change.ChangeDescription;
import org.eclipse.emf.ecore.change.util.ChangeRecorder;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.Resource.IOWrappedException;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.uml2.uml.Model;

import com.cea.papyrus.core.editor.ModelManager;

import edu.mse.camel.client.core.events.model.ModelUpdateEvent2;
import edu.mse.camel.client.eventbus.pubsub.EventManager;
import edu.mse.camel.client.events.peer.SendGenericPeerEvent;

public class CamelChangeRecorder extends ChangeRecorder {

	protected EObject root;
	protected ModelManager modelManager;
		
	public CamelChangeRecorder(EObject rootObject, ModelManager modelManager) {
		super(rootObject);
		this.root = rootObject;
		this.modelManager = modelManager;
	}

	public CamelChangeRecorder(Resource resource) {
		super(resource);
		// TODO Auto-generated constructor stub
	}

	public CamelChangeRecorder(ResourceSet resourceSet) {
		super(resourceSet);
		// TODO Auto-generated constructor stub
	}
	
	@Override
	public void notifyChanged(Notification notification) {
		super.notifyChanged(notification);
	}
	
	public void save() {
		
		boolean removed = false;
		ChangeDescription c = null;
		try {
			ResourceSet rSet = root.eResource().getResourceSet();
			Resource cdResource = null;
			if (root instanceof Model) {
				cdResource = rSet.createResource(root.eResource().getURI());
			} else {
				cdResource = rSet.createResource(root.eResource().getURI());
			}
			c = this.endRecording();
			if (c != null) {
				//tempRemoveAdapter();
				removed = true;
					c.applyAndReverse();
					publishEvent(cdResource, c);
					c.applyAndReverse();
				if (removed) {
					this.beginRecording(Collections.singletonList(root));
					removed = false;
				}
			}
		} catch (IOWrappedException iowe) {
			iowe.printStackTrace();
			if (removed) {
				c.applyAndReverse();
				this.beginRecording(Collections.singletonList(root));
				removed = false;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
/*	
	@Override
	public void notifyChangedB(Notification notification) {
		
		if (notification.getEventType() == Notification.REMOVING_ADAPTER) {
			return;
		}
		boolean removed = false;
		ChangeDescription c = null;
		try {
			super.notifyChanged(notification);
			ResourceSet rSet = root.eResource().getResourceSet();
			Resource cdResource = null;
			if (root instanceof Model) {
				cdResource = rSet.createResource(root.eResource().getURI());
			} else {
				cdResource = rSet.createResource(root.eResource().getURI());
			}
			c = this.endRecording();
			if (c != null) {
				//tempRemoveAdapter();
				removed = true;
				if (notification.getFeature() instanceof EReference) {
					EReference reference = (EReference) notification.getFeature();
					if (reference.isContainment()) {
						c.applyAndReverse();
						publishEvent(cdResource, c);
						c.applyAndReverse();
					}
				} else {
					c.applyAndReverse();
					publishEvent(cdResource, c);
					c.applyAndReverse();
				}
				if (removed) {
					this.beginRecording(Collections.singletonList(root));
					removed = false;
				}
			}
		} catch (IOWrappedException iowe) {
			iowe.printStackTrace();
			if (removed) {
				c.applyAndReverse();
				this.beginRecording(Collections.singletonList(root));
				removed = false;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
*/
	private void tempRemoveAdapter() {
		TreeIterator<EObject> tree = 
			EcoreUtil.getAllContents(Collections.singleton(root));
		while (tree.hasNext()) {
			EObject eObject = tree.next();
			eObject.eAdapters().remove(this);
		}
	}

	static int seqence = 0;
	private void publishEvent(Resource cdResource, ChangeDescription c)
			throws IOException {
		cdResource.getContents().add(c);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		
		cdResource.save(new FileOutputStream(new File("c:\\temp\\sender_2_" + seqence + ".xml")), null);
		seqence++;
		
		cdResource.save(baos, null);
		ModelUpdateEvent2 me2 = new ModelUpdateEvent2(getKind());
		me2.setByteArray(baos.toByteArray());
		SendGenericPeerEvent sent = new SendGenericPeerEvent();
		sent.writeObject(me2);
		EventManager.getInstance().dispatchEventAsynchronous(sent);
	}
	
	protected ModelUpdateEvent2.KIND getKind() {
		if (root instanceof Model) {
			return ModelUpdateEvent2.KIND.UML;
		} else {
			return ModelUpdateEvent2.KIND.DI2;
		}
	}
	

}
